#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>


//****************UDP*************************
//****************服务器**********************

////用到的接口
////创建socket文件描述符(客户端+服务器端，TCP/UDP)
//int socket(int domain,int type,int protocol);
////绑定端口号(服务器 TCP,UDP)
//int bind(int socket,const struct  sockaddr *address,socklen_t address_len);
////服务器开始监听，被动状态，可以被建立连接(服务器端 TCP)
//int listen(int socket,int backlog);
////接收请求(服务器端 TCP)
//int accept(int socket,struct sockaddr *address,socklen_t address_len);
////建立连接(客户端 TCP)
//int connect(int sockfd,const struct sockaddr *addr,socklen_t address_len);


//0,绑定端口号
//1,接收客户端的请求（request）
//2,经过计算处理，做出响应
//   因为此处是echo_server 回显服务，所以省去计算处理，只做以下几步处理
//   a)接收到请求后，将其保存下来
//   b)显示到标准输出
//3,将响应发送给客户端


// ./service [IP] [Port]
//  要绑定的IP地址和端口号
int main(int argc ,char * argv[])
{
  //判断命令行参数是否正确
  if(argc!=3)
  {
    printf("Usage:./service [IP] [Port]\n");
    return 0;
  }

  //****************创建socket套接字*********************************
  int fd=socket(AF_INET,SOCK_DGRAM,0);
  if(fd<0)
  {
    perror("socket");
    exit(1);
  }

  //***************将所要绑定的IP地址和Port信息放到sockaddr_in结构体中
  sockaddr_in addr;
  addr.sin_family=AF_INET;
  //要将字符串格式的点分十进制的IP地址转换为数字
  //用到了inet_addr()函数
  addr.sin_addr.s_addr=inet_addr(argv[1]);

  //要将端口号转换为数字,并且转换位网络字节序
  addr.sin_port=htons(atoi(argv[2]));
  socklen_t sock_len=sizeof(addr);


  //***************服务器绑定端口号*************************************
  if((bind(fd,(sockaddr *)&addr,sock_len))<0)
  {
    perror("bind");
    exit(2);
  }
  printf("bind success\n");
  //**************服务器进行事件循环************************************
  char buf[1024]={0};
  sockaddr_in client;
  socklen_t client_len=sizeof(client);

  while(1)
  {
    //1.接收来自客户端的请求
    ssize_t read_size=recvfrom(fd,buf,sizeof(buf)-1,0,(sockaddr *)&client,&client_len); 
    //注意：这里的client_len 既是输出型参数（接收的最大长度）。又是输入型参数（允许最大长度）
    if(read_size<0)
    {
      //读取错误
      printf("读取失败\n");
      continue;
    }
    if(read_size==0)
    {
      //读到问价结束，表示当前客户端已经关闭socket
      printf("read done\n");
      return 0;
    }
    else
    {
      buf[read_size]='\0';
      //2.将收到的内容显示到标准输出
      
      printf("client: %s:%d say %s",inet_ntoa(client.sin_addr),ntohs(client.sin_port),buf);
      fflush(stdout);
      //3.收到的内容发回给客户端
      sendto(fd,buf,read_size,0,(sockaddr *)&client,client_len);
    }
  }
  close(fd);

}
